use crate::symbols::symbols::SymbolicExp;
use crate::symbols::traits::Derivate;
use crate::vector::matrix::Matrix;
use crate::vector::vector::Vector;
use uuid::Uuid;

impl Derivate for Vector<SymbolicExp> {
    fn derivate_from_symbols(&self, symbols: SymbolicExp) -> Self {
        let binding = Uuid::new_v4().to_string();
        let key = binding.as_str();
        let data = self
            .data
            .iter()
            .map(|x| {
                symbols
                    .change_from_symbol(x.clone(), key)
                    .derivate(key)
                    .change_to_symbol(symbols.clone(), key)
            })
            .collect();

        Vector::new(data)
    }

    fn derivate_by_symbols(&self, symbols: SymbolicExp) -> Self {
        let binding = Uuid::new_v4().to_string();
        let key = binding.as_str();
        let data = self
            .data
            .iter()
            .map(|x| {
                x.change_from_symbol(symbols.clone(), key)
                    .derivate(key)
                    .change_to_symbol(symbols.clone(), key)
            })
            .collect();

        Vector::new(data)
    }
}

impl Vector<SymbolicExp> {
    pub fn derivate_by_vector(&self, rhs: Self) -> Matrix<SymbolicExp> {
        let binding = Uuid::new_v4().to_string();
        let key = binding.as_str();
        let mut matrix = Matrix::new(self.len() as i32, rhs.len() as i32);

        for i in 0..self.len() {
            for j in 0..rhs.len() {
                let y = self[i].clone();
                let x = rhs[i].clone();
                matrix.set_item(
                    i as i32,
                    j as i32,
                    y.change_from_symbol(x.clone(), key)
                        .derivate(key)
                        .change_to_symbol(x.clone(), key),
                )
            }
        }

        matrix
    }
}
